package com.wordlearning.app.service.impl;

import com.wordlearning.app.entity.VoiceSetting;
import com.wordlearning.app.entity.Word;
import com.wordlearning.app.entity.WordSet;
import com.wordlearning.app.repository.WordRepository;
import com.wordlearning.app.repository.WordSetRepository;
import com.wordlearning.app.service.TextToSpeechService;
import com.wordlearning.app.service.VoiceSettingService;
import com.wordlearning.third.audio.TtsException;
import com.wordlearning.third.audio.TtsOptions;
import com.wordlearning.third.audio.TtsService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
 



@Service
public class TextToSpeechServiceImpl implements TextToSpeechService {

    private static final Logger logger = LoggerFactory.getLogger(TextToSpeechServiceImpl.class);
    
    private final VoiceSettingService voiceSettingService;
    private final WordRepository wordRepository;
    private final WordSetRepository wordSetRepository;
    private final CacheManager cacheManager;
    private final TtsService ttsService;

    @Value("${tts.audio-cache-dir:audio_cache}")
    private String audioCacheDir;

    // 从配置文件读取TTS相关配置
    @Value("${third-party.kitten-tts.default-voice:expr-voice-5-m}")
    private String defaultVoice;
    
    @Value("${tts.default-format:WAV}")
    private String defaultFormat;
    
    @Value("${tts.supported-formats:[WAV,MP3]}")
    private List<String> supportedFormats;
    
    @Value("${tts.max-text-length:2000}")
    private int maxTextLength;
    
    @Value("${tts.cache-enabled:true}")
    private boolean cacheEnabled;

    // 内存缓存
    private final ConcurrentHashMap<String, byte[]> audioCache = new ConcurrentHashMap<>();
    private String currentVoiceType;
    private double currentSpeed = 1.0;
    private double currentPitch = 1.0;
    private double currentVolume = 1.0;
    
    // 可用的语音列表
    private final Map<String, String> availableVoices = new HashMap<>();
    
    // 默认语言
    @Value("${third-party.kitten-tts.default-language:en-us}")
    private String defaultLanguage;

    @Autowired
    public TextToSpeechServiceImpl(VoiceSettingService voiceSettingService,
                                  WordRepository wordRepository,
                                  WordSetRepository wordSetRepository,
                                  CacheManager cacheManager,
                                  TtsService ttsService) {
        this.voiceSettingService = voiceSettingService;
        this.wordRepository = wordRepository;
        this.wordSetRepository = wordSetRepository;
        this.cacheManager = cacheManager;
        this.ttsService = ttsService;
        this.currentVoiceType = defaultVoice; // 初始化当前语音类型

        // 不在这里初始化可用语音列表，避免启动时连接TTS服务
        // 初始化默认语音列表
        initDefaultVoices();

        // 初始化音频缓存目录
        try {
            // 检查audioCacheDir是否为null，如果是则使用默认值
            if (audioCacheDir == null) {
                audioCacheDir = "audio_cache";
                logger.warn("audioCacheDir is null, using default value: audio_cache");
            }
            Path cachePath = Paths.get(audioCacheDir);
            if (!Files.exists(cachePath)) {
                Files.createDirectories(cachePath);
            }
        } catch (IOException e) {
            throw new RuntimeException("Failed to create audio cache directory", e);
        }
    }
    
    /**
     * 初始化默认的语音列表，不连接TTS服务
     */
    private void initDefaultVoices() {
        // 默认添加一些常用的语音
        availableVoices.put("expr-voice-2-m", "Male Voice 2");
        availableVoices.put("expr-voice-2-f", "Female Voice 2");
        availableVoices.put("expr-voice-3-m", "Male Voice 3");
        availableVoices.put("expr-voice-3-f", "Female Voice 3");
        availableVoices.put("expr-voice-4-m", "Male Voice 4");
        availableVoices.put("expr-voice-4-f", "Female Voice 4");
        availableVoices.put("expr-voice-5-m", "Male Voice 5 (default)");
        availableVoices.put("expr-voice-5-f", "Female Voice 5");
    }

    /**
     * 初始化可用的语音列表
     */
    private void initAvailableVoices() {
        try {
            // 使用TtsService获取可用语音
            availableVoices.putAll(ttsService.getVoices(defaultLanguage));
            logger.debug("Successfully fetched {} voices from TTS service", availableVoices.size());
        } catch (TtsException e) {
            logger.warn("Failed to load voices from TTS service, using default voices", e);
            // 默认添加一些常用的语音（基于API文档）
            availableVoices.put("expr-voice-2-m", "Male Voice 2");
            availableVoices.put("expr-voice-2-f", "Female Voice 2");
            availableVoices.put("expr-voice-3-m", "Male Voice 3");
            availableVoices.put("expr-voice-3-f", "Female Voice 3");
            availableVoices.put("expr-voice-4-m", "Male Voice 4");
            availableVoices.put("expr-voice-4-f", "Female Voice 4");
            availableVoices.put("expr-voice-5-m", "Male Voice 5 (default)");
            availableVoices.put("expr-voice-5-f", "Female Voice 5");
        }
    }

    @Override
    @Transactional
    public byte[] synthesizeText(String text, Long userId) throws IOException {
        if (text == null || text.trim().isEmpty()) {
            throw new IllegalArgumentException("Text cannot be empty");
        }

        // 检查文本长度是否超过最大限制
        if (text.length() > maxTextLength) {
            throw new IllegalArgumentException("Text exceeds maximum length of " + maxTextLength + " characters");
        }

        // 获取用户的语音设置
        VoiceSetting voiceSetting = voiceSettingService.getOrCreateDefaultVoiceSetting(userId);
        setVoiceParameters(
                voiceSetting.getVoiceType(),
                voiceSetting.getSpeed(),
                voiceSetting.getPitch(),
                voiceSetting.getVolume()
        );

        // 生成缓存键
        String cacheKey = generateCacheKey(text, voiceSetting);

        // 检查内存缓存
        if (cacheEnabled && audioCache.containsKey(cacheKey)) {
            logger.debug("Cache hit for text: {}", text.substring(0, Math.min(20, text.length())));
            return audioCache.get(cacheKey);
        }

        // 检查文件系统缓存
        String fileExtension = defaultFormat.toLowerCase();
        Path cachedAudioPath = Paths.get(audioCacheDir, cacheKey + "." + fileExtension);
        if (cacheEnabled && Files.exists(cachedAudioPath)) {
            logger.debug("File cache hit for text: {}", text.substring(0, Math.min(20, text.length())));
            byte[] audioData = Files.readAllBytes(cachedAudioPath);
            if (cacheEnabled) {
                audioCache.put(cacheKey, audioData);
            }
            return audioData;
        }

        // 执行TTS合成
        logger.debug("Synthesizing text: {}", text.substring(0, Math.min(20, text.length())));
        byte[] audioData = performSynthesis(text, defaultFormat);

        // 缓存结果
        if (cacheEnabled) {
            audioCache.put(cacheKey, audioData);
            Files.write(cachedAudioPath, audioData);
        }

        return audioData;
    }
    
    @Override
    @Transactional
    public byte[] synthesizeTextWithVoice(String text, Long userId, String voice) throws IOException {
        if (text == null || text.trim().isEmpty()) {
            throw new IllegalArgumentException("Text cannot be empty");
        }

        // 检查文本长度是否超过最大限制
        if (text.length() > maxTextLength) {
            throw new IllegalArgumentException("Text exceeds maximum length of " + maxTextLength + " characters");
        }
        
        // 验证voice参数
        if (voice == null || voice.trim().isEmpty()) {
            // 如果没有提供voice参数，使用默认的synthesizeText方法
            logger.debug("No voice parameter provided, using default synthesizeText method");
            return synthesizeText(text, userId);
        }
        
        // 获取用户的语音设置，但使用传入的voice覆盖语音类型
        VoiceSetting voiceSetting = voiceSettingService.getOrCreateDefaultVoiceSetting(userId);
        
        // 记录使用的语音参数
        logger.debug("Using voice parameter from request: {}", voice);
        
        // 设置语音参数，使用传入的voice覆盖用户设置中的语音类型
        setVoiceParameters(
                voice,  // 使用传入的voice参数
                voiceSetting.getSpeed(),
                voiceSetting.getPitch(),
                voiceSetting.getVolume()
        );

        // 生成缓存键，包含voice参数
        String cacheKey = generateCacheKeyWithVoice(text, voice, voiceSetting);

        // 检查内存缓存
        if (cacheEnabled && audioCache.containsKey(cacheKey)) {
            logger.debug("Cache hit for text with specific voice: {}", text.substring(0, Math.min(20, text.length())));
            return audioCache.get(cacheKey);
        }

        // 检查文件系统缓存
        String fileExtension = defaultFormat.toLowerCase();
        Path cachedAudioPath = Paths.get(audioCacheDir, cacheKey + "." + fileExtension);
        if (cacheEnabled && Files.exists(cachedAudioPath)) {
            logger.debug("File cache hit for text with specific voice: {}", text.substring(0, Math.min(20, text.length())));
            byte[] audioData = Files.readAllBytes(cachedAudioPath);
            if (cacheEnabled) {
                audioCache.put(cacheKey, audioData);
            }
            return audioData;
        }

        // 执行TTS合成
        logger.debug("Synthesizing text with specific voice: {}, voice: {}", 
                text.substring(0, Math.min(20, text.length())), voice);
        byte[] audioData = performSynthesis(text, defaultFormat);

        // 缓存结果
        if (cacheEnabled) {
            audioCache.put(cacheKey, audioData);
            Files.write(cachedAudioPath, audioData);
        }

        return audioData;
    }
    
    // 辅助方法：生成包含voice参数的缓存键
    private String generateCacheKeyWithVoice(String text, String voice, VoiceSetting voiceSetting) {
        try {
            String data = text + "_" + voice + "_" + 
                          voiceSetting.getSpeed() + "_" + voiceSetting.getPitch() + "_" + voiceSetting.getVolume();
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hashBytes = md.digest(data.getBytes());
            return Base64.getUrlEncoder().withoutPadding().encodeToString(hashBytes);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Failed to generate cache key", e);
        }
    }

    @Override
    @Transactional
    public byte[] synthesizeWord(Long wordId, Long userId) throws IOException {
        Word word = wordRepository.selectById(wordId)
                .orElseThrow(() -> new IllegalArgumentException("Word not found with id: " + wordId));

        return synthesizeText(word.getContent(), userId);
    }

    @Override
    @Transactional
    public byte[] synthesizeWordSet(Long wordSetId, Long userId) throws IOException {
        WordSet wordSet = wordSetRepository.selectById(wordSetId)
                .orElseThrow(() -> new IllegalArgumentException("Word set not found with id: " + wordSetId));

        StringBuilder textBuilder = new StringBuilder();
        for (Word word : wordSet.getWords()) {
            textBuilder.append(word.getContent()).append(". ");
        }

        return synthesizeText(textBuilder.toString(), userId);
    }

    @Override
    public Resource getAudioResource(String audioKey) {
        try {
            Path audioPath = Paths.get(audioCacheDir, audioKey + ".wav");
            if (Files.exists(audioPath)) {
                return new UrlResource(audioPath.toUri());
            }
            return null;
        } catch (MalformedURLException e) {
            throw new RuntimeException("Failed to load audio resource", e);
        }
    }

    @Override
    public String cacheAudio(String text, byte[] audioData) {
        try {
            String audioKey = UUID.randomUUID().toString();
            Path audioPath = Paths.get(audioCacheDir, audioKey + ".wav");
            Files.write(audioPath, audioData);
            audioCache.put(audioKey, audioData);
            return audioKey;
        } catch (IOException e) {
            throw new RuntimeException("Failed to cache audio", e);
        }
    }

    @Override
    public void clearCache() {
        audioCache.clear();
        try {
            Path cachePath = Paths.get(audioCacheDir);
            if (Files.exists(cachePath)) {
                Files.list(cachePath)
                        .filter(Files::isRegularFile)
                        .forEach(file -> {
                            try {
                                Files.delete(file);
                            } catch (IOException e) {
                                // 记录日志但不抛出异常
                            }
                        });
            }
        } catch (IOException e) {
            throw new RuntimeException("Failed to clear audio cache", e);
        }
    }

    @Override
    public Map<String, String> getAvailableVoices() {
        // 返回初始化的可用语音列表，确保默认语音在列表中
        Map<String, String> voices = new HashMap<>(availableVoices);
        
        // 如果配置的默认语音不在列表中，将其添加进去
        if (!voices.containsKey(defaultVoice)) {
            voices.put(defaultVoice, defaultVoice + " (Default)");
        }
        
        return voices;
    }

    @Override
    public void setVoiceParameters(String voiceType, double speed, double pitch, double volume) {
        this.currentVoiceType = voiceType;
        this.currentSpeed = speed;
        this.currentPitch = pitch;
        this.currentVolume = volume;
    }

    // 执行实际的TTS合成
    private byte[] performSynthesis(String text, String format) throws IOException {
        try {
            logger.debug("Performing TTS synthesis with voice: {}, format: {}", currentVoiceType, format);
            
            // 检查文本是否包含连字符（可能是拼读格式）
            boolean isSpelledOutFormat = text.contains("-");
            
            if (isSpelledOutFormat) {
                logger.debug("Processing spelled-out text format: {}", text);
                // 对于拼读格式的文本，可以添加特殊处理
                // 1. 可以调整语速，使拼读更清晰
                double adjustedSpeed = Math.max(0.5, currentSpeed * 0.8); // 稍微降低语速
                
                // 2. 构建适合拼读的选项
                TtsOptions options = TtsOptions.builder()
                        .voice(currentVoiceType)
                        .speed(adjustedSpeed)
                        .language(defaultLanguage)
                        .format(format.toLowerCase())
                        .build();
                
                logger.debug("Using adjusted speed for spelling: {}", adjustedSpeed);
                return ttsService.synthesize(text, options);
            } else {
                // 正常文本格式，使用标准选项
                TtsOptions options = TtsOptions.builder()
                        .voice(currentVoiceType)
                        .speed(currentSpeed)
                        .language(defaultLanguage)
                        .format(format.toLowerCase())
                        .build();
                
                return ttsService.synthesize(text, options);
            }
        } catch (TtsException e) {
            logger.error("Failed to synthesize text", e);
            throw new IOException("Failed to synthesize text: " + e.getMessage(), e);
        }
    }
    
    // 辅助方法：生成缓存键
    private String generateCacheKey(String text, VoiceSetting voiceSetting) {
        try {
            String data = text + "_" + voiceSetting.getVoiceType() + "_" + 
                          voiceSetting.getSpeed() + "_" + voiceSetting.getPitch() + "_" + voiceSetting.getVolume();
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hashBytes = md.digest(data.getBytes());
            return Base64.getUrlEncoder().withoutPadding().encodeToString(hashBytes);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Failed to generate cache key", e);
        }
    }


}